/**
 * 
 */
package server.tests;

import static org.junit.Assert.*;

import java.util.List;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import forum.Forum;
import forum.Member;
import server.controller.Controller;

/**
 * @author Olga
 * 
 */
public class ControllerTest {

	Controller controller;

	/**
	 * @throws java.lang.Exception
	 */
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
	}

	/**
	 * @throws java.lang.Exception
	 */
	@AfterClass
	public static void tearDownAfterClass() throws Exception {
	}

	/**
	 * @throws java.lang.Exception
	 */
	@Before
	public void setUp() throws Exception {
		this.controller = new Controller();
		this.controller.login("Olgasib", "1234");
		this.controller.login("Masha", "gxyze");
	}

	/**
	 * @throws java.lang.Exception
	 */
	@After
	public void tearDown() throws Exception {
	}

	@Test
	public void testRegisterUser(){
		//successful logging in
		int ansRight = this.controller.registerUser("uname","fname", "lname", "pw", "mail@gmail.com", 'f');
		assertEquals(0, ansRight);
		//one or more of the parameters are empty or null
		int ansWrong1 = this.controller.registerUser("uname1", "fName1", "lName1", "", null, 'm');
		assertEquals(-3, ansWrong1);
		//user with such username exists
		int ansWrong2 = this.controller.registerUser("uname", "fname2", "lname2", "pw2", "mail2@gmail.com", 'm');
		assertFalse(ansWrong2 >= 0);
		//the user is already registered
		int ansWrong3 = this.controller.registerUser("uname","fname", "lname", "pw", "mail@gmail.com", 'f');
		assertFalse(ansWrong3 >= 0);
		//we work on the real database and we don't want to change its state because of the 
		//tests so we remove registered user now
		this.controller.removeUser("uname");
	}
	/**
	 * Test method for
	 * {@link Controller.Storage#login(java.lang.String, java.lang.String)}.
	 */
	@Test
	public void testLogin() {
		//the login action is successful
		this.controller.registerUser("uname","fname", "lname", "pw", "mail@gmail.com", 'f');
		int ansRight = this.controller.login("uname", "pw");
		assertEquals(0, ansRight);
		//the user is not registered
		int ansWrong1 = this.controller.login("uname1", "pw");
		assertTrue(ansWrong1 < 0);
		//the user is trying to login with incorrect password
		int ansWrong2 = this.controller.login("uname", "pw1");
		assertTrue(ansWrong2 < 0);
		//we work on the real database and we don't want to change its state because of the 
		//tests so we remove registered and logged in user now
		this.controller.logoff("uname");
		this.controller.removeUser("uname");
	}

	/**
	 * Test method for {@link Controller.Storage#loggoff(java.lang.String)}.
	 */
	@Test
	public void testLoggoff() {
		this.controller.registerUser("uname","fname", "lname", "pw", "mail@gmail.com", 'f');
		this.controller.login("uname", "pw");
		//the logging out was successful
		int ansRight = this.controller.logoff("uname");
		assertEquals(0, ansRight);
		//the user is already logged out
		int ansWrong = this.controller.logoff("uname");
		assertTrue(ansWrong < 0);
		//we work on the real database and we don't want to change its state because of the 
		//tests so we remove registered user now
		this.controller.removeUser("uname");
	}

	/**
	 * Test method for
	 * {@link Controller.Storage#removeUser(java.lang.String, java.lang.String)}.
	 */
	@Test
	public void testRemoveUser() {
		this.controller.registerUser("uname","fname", "lname", "pw", "mail@gmail.com", 'f');
		//removing of user was successful
		int ansRight = this.controller.removeUser("uname");
		assertEquals(0, ansRight);
		//removing of user failed. the user is already removed
		int ansWrong = this.controller.removeUser("uname");
		assertTrue(ansWrong < 0);
	}

	/**
	 * Test method for
	 * {@link Controller.Storage#addUserFriend(java.lang.String, java.lang.String)}
	 *
	 */
	@Test
	public void testAddUserFriend() {
		this.controller.registerUser("uname","fname", "lname", "pw", "mail@gmail.com", 'f');
		this.controller.registerUser("uname1","fname1", "lname1", "pw1", "mail1@gmail.com", 'f');
		this.controller.login("uname", "pw");
		//the adding of the friend is successful
		int ansRight = this.controller.addUserFriend("uname", "uname1");
		assertEquals(0, ansRight);
		//the adding has failed, uname2 is not registered
		int ansWrong1 = this.controller.addUserFriend("uname", "uname2");
		assertTrue(ansWrong1 < 0);
		//the adding was failed. user can not add himself
		int ansWrong2 = this.controller.addUserFriend("uname", "uname");
		assertTrue(ansWrong2 < 0);
		//the adding has failed. uname1 is already in the uname's friends' list
		int ansWrong3 = this.controller.addUserFriend("uname", "uname1");
		assertTrue(ansWrong3 < 0);
		//we work on the real database and we don't want to change its state because of the 
		//tests so we remove registered and logged in users now
		this.controller.logoff("uname");
		this.controller.removeUser("uname");
		this.controller.removeUser("uname1");
		
	}

	/**
	 * Test method for
	 * {@link Controller.Storage#removeUserFriend(java.lang.String, java.lang.String)}
	 * 
	 */
	@Test
	public void testRemoveUserFriend() {
		this.controller.registerUser("uname","fname", "lname", "pw", "mail@gmail.com", 'f');
		this.controller.registerUser("uname1","fname1", "lname1", "pw1", "mail1@gmail.com", 'f');
		this.controller.registerUser("uname2","fname2", "lname2", "pw2", "mail2@gmail.com", 'f');
		this.controller.login("uname", "pw");
		this.controller.login("uname2", "pw2");
		this.controller.addUserFriend("uname", "uname1");
		this.controller.addUserFriend("uname2", "uname1");
		//removing of friend was successful
		int ansRight = this.controller.removeUserFriend("uname", "uname1");
		assertEquals(0, ansRight);
		//removing of friend failed because uname2 is not logged in
		this.controller.logoff("uname2");
		int ansWrong1 = this.controller.removeUserFriend("uname2", "uname1");
		assertTrue(ansWrong1 < 0);
		//removing of friend has failed because uname3 does not exist in the system
		int ansWrong2 = this.controller.removeUserFriend("uname", "uname3");
		assertTrue(ansWrong2 < 0);
		//we work on the real database and we don't want to change its state because of the 
		//tests so we remove registered and logged in users now
		this.controller.logoff("uname");
		this.controller.logoff("uname2");
		this.controller.removeUser("uname");
		this.controller.removeUser("uname1");
		this.controller.removeUser("uname2");	
	}

	/**
	 * Test method for
	 * {@link Controller.Storage#addForum(java.lang.String, java.lang.String)}.
	 */
	@Test
	public void testAddForumWeb() {
		// logged in moderator adds Forum
		int idOfForum = this.controller.addForumWeb("ForumSubject0");
		assertTrue(idOfForum > 0);
		// forum is already exist
		assertTrue(this.controller.addForumWeb("ForumSubject0") < 0 );
		assertTrue(this.controller.addForumWeb("") < 0 );
		//we work on the real database and we don't want to change its state because of the 
		//tests so we remove registered and logged in users and added forums now
		this.controller.removeForum("Olgasib", idOfForum);
	}

	/**
	 * Test method for
	 * {@link Controller.Storage#addThread(int, java.lang.String, java.lang.String, java.lang.String)}
	 * .
	 */
	@Test
	public void testAddThread() {
		int id1 = this.controller.addForumWeb("ForumSubject0");
		int id2 = this.controller.addForumWeb("ForumSubject1");
		// logged in moderator adding the thread
		int idthread1 = this.controller.addThread(id1, "subject0ForForum0",
				"content", "Olgasib");
		assertTrue(idthread1 > 0);	
		// logged off moderator tried to add thread
		assertTrue(this.controller.addThread(id1, "subject", "content", "Alonsgl") <= 0);
		
		this.controller.registerUser("notModerator", "fName", "lName", "pw", "mail", 'm');
		this.controller.login("notModerator", "pw");
		// simple user adds thread
		int idthread2 = this.controller.addThread(id1, "subject1ForForum0",
				"content", "notModerator");
		System.out.println("idthread2 = "+idthread2);
		assertTrue(idthread2 > 0);
		// not registered user adds thread
		assertTrue(this.controller.addThread(id1, "subject2ForForum0",
				"content", "notRegistered") <= 0);
		// simple user adds thread
		int idthread3 = this.controller.addThread(id2, "subject2ForForum1",
				"content", "notModerator");
		assertTrue(idthread3 > 0);
		// add thread to forumID, which does not exist
		assertTrue(this.controller.addThread(100, "subject2ForForum1",
				"content", "notModerator") <= 0);
		// thread with empty subject
		assertTrue(this.controller.addThread(id2, "", "content", "Olgasib") <= 0);
		// thread with null subject
		assertTrue(this.controller.addThread(id1, null, "content", "Olgasib") <= 0);	
		//we work on the real database and we don't want to change its state because of the 
		//tests so we remove registered and logged in users and added forums and threads now
		this.controller.removeThread("Olgasib", id1, idthread1);
		this.controller.removeThread("notModerator", id1, idthread2);
		this.controller.removeThread("notModerator", id2, idthread3);
		this.controller.removeForum("Olgasib", id1);
		this.controller.removeForum("Masha", id2);
		this.controller.logoff("notModerator");
		this.controller.removeUser("notModerator");

	}

	/**
	 * Test method for
	 * {@link Controller.Storage#addPost(int, int, int, java.lang.String, java.lang.String, java.lang.String)}
	 * .
	 */
	@Test
	public void testAddPost() {
		int id1 = this.controller.addForum("ForumSubject0", "Olgasib");
		int threadId1 = this.controller.addThread(id1, "subject0ForForum0", "content", "Olgasib");
		// logged in moderator adds post
		int postID = this.controller.addPost(id1, threadId1, "postSubject0",
				"content", "Olgasib");
		assertTrue(postID > 0);
		//not existing user tryies to add reply
		assertTrue(this.controller.addPost(id1, threadId1, "subject1", "content1", "uname") <= 0);
		this.controller.registerUser("uname1", "fName1", "lName1", "pw", "mail1@gmail.com", 'f');
		//not logged in user tries to add post
		assertTrue(this.controller.addPost(id1, threadId1, "subject2", "content2", "uname1") <= 0);
		// empty subject
		assertTrue(this.controller.addPost(id1, threadId1, "", "content", "Olgasib") <= 0);
		// null subject
		assertFalse(this.controller.addPost(id1, threadId1, null, "content", "Olgasib") > 0);
		//trying to add to the thread that does not exist
		assertFalse(this.controller.addPost(id1, 1, "subject3", "content3", "Olgasib") > 0);
		//we work on the real database and we don't want to change its state because of the 
		//tests so we remove registered and logged in users and added forums, threads and
		//posts now
		this.controller.removePost("Olgasib", id1, postID);
		this.controller.removeThread("Olgasib", id1, threadId1);
		this.controller.removeForum("Olgasib", id1);
		this.controller.removeUser("uname1");
	}

	/**
	 * Test method for
	 * {@link Controller.Storage#removePost(java.lang.String, int, int, int)}.
	 */
	@Test
	public void testRemovePost() {
		int forumId = this.controller.addForum("subject0", "Olgasib");
		int threadId = this.controller.addThread(forumId, "thread0", "c0", "Olgasib");
	    int postId1 = this.controller.addPost(forumId, threadId, "post1", "content", "Masha");
		int postId2 = this.controller.addPost(forumId, threadId, "post2", "content", "Olgasib");
		//logged in and registered user deletes his post
		assertTrue(this.controller.removePost("Masha", forumId, postId1) >= 0);
	
		this.controller.registerUser("notAuthor", "fName", "lName", "pw", "mail",
		'm');
		this.controller.login("notAuthor", "pw");
		//logged in and registered user tries to delete not his post
		assertFalse(this.controller.removePost("notAuthor", forumId, postId2) >= 0);
		
		this.controller.registerUser("notLoggedIn", "fName1", "lName1", "pw1", "mail",
		'f');
		//not logged in  user tries to delete not his post
		assertFalse(this.controller.removePost("notLoggedIn", forumId, postId2) >= 0);
		
		//trying to delete already deleted post
		assertFalse(this.controller.removePost("Masha", forumId, postId1) >= 0);
		
		//we work on the real database and we don't want to change its state because of the 
		//tests so we remove registered and logged in users and added forums, threads and
		//posts now
		this.controller.removePost("Olgasib", forumId, postId2);
		this.controller.removeThread("Olgasib", forumId, threadId);
		this.controller.removeForum("Olgasib", forumId);
		this.controller.logoff("notAuthor");
		this.controller.removeUser("notAuthor");
		this.controller.removeUser("notLoggedIn");
		
	}
	

	/**
	 * Test method for
	 * {@link Controller.Storage#removeThread(java.lang.String, int, int)}.
	 */
	@Test
	public void testRemoveThread() {
		
		int forumId = this.controller.addForum("subject0", "Olgasib");
		int threadId1 = this.controller.addThread(forumId, "thread0", "c0", "Olgasib");
		int threadId2 = this.controller.addThread(forumId, "thread1", "c0", "Masha");
		this.controller.registerUser("notModerator", "fName", "lName", "pw", "mail",
				'f');
		this.controller.login("notModerator", "pw");
		int threadId3 = this.controller.addThread(forumId, "thread2", "c0", "notModerator");
		int threadId4 = this.controller.addThread(forumId, "thread3", "c0", "notModerator");
		//moderator removes thread that was published by another moderator
		assertEquals(0, this.controller.removeThread("Olgasib", forumId, threadId2));
		//moderator removes thread that was published by not moderator
		assertEquals(0, this.controller.removeThread("Olgasib", forumId, threadId3));
		//user removes thread that was published by user
		assertEquals(0, this.controller.removeThread("notModerator", forumId, threadId4));
		//logged out removes thread
		assertTrue(this.controller.removeThread("Alonsgl", forumId, threadId1) < 0);
		//not registered removes thread
		assertTrue(this.controller.removeThread("notRegistered", forumId, threadId1) < 0);
		//not moderator removes thread that was published by another user
		assertTrue(this.controller.removeThread("notModerator", forumId, threadId1) < 0);
		//we work on the real database and we don't want to change its state because of the 
		//tests so we remove registered and logged in users and added forums now
		this.controller.removeForum("Olgasib", forumId);
		this.controller.logoff("notModerator");
		this.controller.removeUser("notModerator");
	}

	/**
	 * Test method for
	 * {@link Controller.Storage#removeForum(java.lang.String, int)}.
	 */
	@Test
	public void testRemoveForum() {
		
		// fail("Not yet implemented");
		int id1 = this.controller.addForum("subject0", "Olgasib");
		int id2 = this.controller.addForum("subject1", "Masha");
		// logged in moderator removes forum, that was added by other moderator
		assertEquals(0, this.controller.removeForum("Masha", id2));
		// logged of moderator removes forum, that was added by other moderator
		assertFalse(this.controller.removeForum("notExist", id1) >= 0);
		// logged user removes forum, that was added by other moderator
		this.controller.registerUser("notModerator", "fName", "lName", "pw", "mail",
				'g');
		this.controller.login("notModerator", "pw");
		assertFalse(this.controller.removeForum("notModerator", id1) >= 0);
		assertFalse(this.controller.removeForum("notRegistered", id1) >= 0);
		//moderator removes not-existing forum
		assertFalse(this.controller.removeForum("Olgasib", 200) >= 0);
		assertFalse(this.controller.removeForum("Olgasib", 700) >= 0);
		//we work on the real database and we don't want to change its state because of the 
		//tests so we remove registered and logged in users now
		this.controller.removeForum("Olgasib", id1);
		this.controller.logoff("notModerator");
		this.controller.removeUser("notModerator");
	}
	
	@Test
	public void testEditPost() {
		int forumId = this.controller.addForum("subject0", "Olgasib");
		int threadId = this.controller.addThread(forumId, "thread0", "c0", "Olgasib");
	    int postId1 = this.controller.addPost(forumId, threadId, "post1", "content", "Masha");
		int postId2 = this.controller.addPost(forumId, threadId, "post2", "content", "Olgasib"); 
		//successful editing
		assertTrue(this.controller.editPost("Masha", forumId, postId1, "content2") >= 0);
		this.controller.registerUser("notModerator", "fName", "lName", "pw", "mail",
		'f');
		this.controller.login("notModerator", "pw");
		//tries to edit post without suitavle authority
		assertFalse(this.controller.editPost("notModerator", forumId, postId2, "content1") >= 0);
		//not registered user tries to edit post
		assertFalse(this.controller.editPost("notRegistered", forumId, postId2, "content1") >= 0);
		this.controller.registerUser("notLoggedIn", "fName", "lName", "pw", "mail",
		'f');
		//not logged in user tries to edit post
		assertFalse(this.controller.editPost("notLoggedIn", forumId, postId2, "content1") >= 0);
		//we work on the real database and we don't want to change its state because of the 
		//tests so we remove registered and logged in users and added forums, threads and
		//posts now
		this.controller.removePost("Masha", forumId, postId1);
		this.controller.removePost("Olgasib", forumId, postId2);
		this.controller.removeThread("Olgasib", forumId, threadId);
		this.controller.removeForum("Olgasib", forumId);
		this.controller.logoff("notModerator");
		this.controller.removeUser("notModerator");
		this.controller.removeUser("notLoggedIn");

	
	}
	

	/**
	 * Test method for {@link Controller.Storage#getThreadsTopicsOfForum(int)}.
	 */
	@Test
	public void testGetThreadsTopicsOfForum() {
		int forumID = this.controller.addForum("subject0", "Olgasib");
		int threadId1 = this.controller.addThread(forumID, "thread0", "c0", "Olgasib");
		int threadId2 = this.controller.addThread(forumID, "thread1", "c1", "Olgasib");
		//the forum exists, so the list of threads is returned
		List<forum.Thread> threads = this.controller.getThreadsTopicsOfForum(forumID);
		assertEquals(2, threads.size());
		assertTrue(threads.get(0).getRoot().getSubject().equals("thread0"));
		assertTrue(threads.get(1).getRoot().getSubject().equals("thread1"));	
		//we work on the real database and we don't want to change its state because of the 
		//tests so we remove added forums and threads now
		this.controller.removeThread("Olgasib", forumID, threadId1);
		this.controller.removeThread("Olgasib", forumID, threadId2);
		this.controller.removeForum("Olgasib", forumID);
	}

	/**
	 * Test method for {@link server.controller.Controller#getThreadsOfTopic(int)}.
	 */
	@Test
	public void testGetThreadsOfTopic() {
		int forumID = this.controller.addForum("subject0", "Olgasib");
		int threadID = this.controller.addThread(forumID, "thread0", "c0", "Olgasib");
		int postID = this.controller.addPost(forumID, threadID, "ans to thread", "content", "Olgasib");
		//succesfull getting of thread
		forum.Thread t = this.controller.getThreadsOfTopic("Olgasib", threadID);
		assertFalse(t == null);
		assertTrue(t.getRoot().getSubject().equals("thread0"));
		//the user is not logged in
		forum.Thread t1 = this.controller.getThreadsOfTopic("notExist", threadID);
		assertTrue(t1==null);
		//we work on the real database and we don't want to change its state because of the 
		//tests so we remove added forums, threads and posts now
		this.controller.removePost("Olgasib", forumID, postID);
		this.controller.removeThread("Olgasib", forumID, threadID);
		this.controller.removeForum("Olgasib", forumID);
	}
	
	public void testGetForums(){
		int forumID1 = this.controller.addForum("subject0", "Olgasib");
		int forumID2 = this.controller.addForum("subject1", "Olgasib");
		int forumID3 = this.controller.addForum("subject2", "Olgasib");
		List<Forum> forums = this.controller.getForums();
		assertTrue(forums.size() > 0);
		//we work on the real database and we don't want to change its state because of the 
		//tests so we remove registered and logged in users and added forums now
		this.controller.removeForum("Olgasib", forumID1);
		this.controller.removeForum("Olgasib", forumID2);
		this.controller.removeForum("Olgasib", forumID3);
	}
	
	
	@Test
	public void testGetFriendsOfUser() {
		this.controller.registerUser("uName", "fName", "lName","pw", "mail", 'm');
		this.controller.registerUser("uName1", "fName1", "lName1","pw1", "mail1", 'f');
		this.controller.registerUser("uName2", "fName2", "lName2","pw2", "mail2", 'm');
		this.controller.registerUser("uName3", "fName3", "lName3","pw3", "mail3", 'm');
		this.controller.login("uName", "pw");
		this.controller.addUserFriend("uName", "uName1");
		this.controller.addUserFriend("uName", "uName2");
		this.controller.addUserFriend("uName", "uName3");
		String ans = "";
		List<Member> friends = this.controller.getFriendsOfUser("uName");
		for (int i = 0; i < friends.size(); i++)
            ans += "friend:"+friends.get(i).getUsername()+"\n";
        ans+="\0";
		assertFalse(ans.isEmpty());
		assertTrue(ans.contains("uName1"));
		assertTrue(ans.contains("uName2"));
		assertTrue(ans.contains("uName3"));
		//the user is not logged in
		List<Member> friends1 = this.controller.getFriendsOfUser("uName1");
		assertTrue(friends1 == null);
		//we work on the real database and we don't want to change its state because of the 
		//tests so we remove registered and logged in users now
		this.controller.logoff("uName");
		this.controller.removeUser("uName");
		this.controller.removeUser("uName1");
		this.controller.removeUser("uName2");
		this.controller.removeUser("uName3");
	}
}
